//
// Copyright (c) 2005 BroadVision, Inc. All rights reserved.
//
// This software is copyrighted.  Under the copyright laws, this software
// may not be copied, in whole or in part, without prior written consent
// of BroadVision, Inc. or its assignees.  This software is provided under
// the terms of a license between BroadVision and the recipient, and its
// use is subject to the terms of that license.
//
// This software may be protected by one or more U.S. and International
// patents.  Certain applications of BroadVision One-To-One software are
// covered by U.S. patent 5,710,887.
//
// TRADEMARKS: BroadVision and BroadVision One-To-One are registered
// trademarks of BroadVision, Inc., in the United States and the European
// Community, and are trademarks of BroadVision, Inc., in other
// countries.  The BroadVision logo, is a trademark of BroadVision, Inc.,
// in the United States and other countries. Additionally, IONA and Orbix
// are trademarks of IONA Technologies, Ltd.  RSA, MD5, and RC2 are
// trademarks of RSA Data Security, Inc.
//

package com.broadvision.manage.common.tools.action.user;

import java.util.List;
import java.util.ArrayList;
import java.util.StringTokenizer;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.commons.collections.FastHashMap;
import org.apache.struts.Globals;

import com.broadvision.visitor.client.Visitor;
import com.broadvision.visitor.client.VisitorManager;
import com.broadvision.visitor.exceptions.NoVisitorException;
import com.broadvision.visitor.exceptions.VisitorInactiveException;
import com.broadvision.visitor.exceptions.VisitorException;
import com.broadvision.portal.services.util.TransferBeanUtils;
import com.broadvision.web.util.ViewDynaBean;

import com.broadvision.data.common.TableData;
import com.broadvision.manage.common.tools.user.UserSearch;
import com.broadvision.manage.common.tools.user.UserProfile;
import com.broadvision.manage.tools.action.BaseAction;

/**
 * Searches users based on some criteria.
 */
public class UserSearchPopupAction extends BaseAction {

  public static final String VIEW_BEAN_NAME = "mtUserSearchPopupView";
  public static final String DTO_BEAN_NAME  = "mtUserSearchPopupDTO";
  public static final String USER_DELIM = "$#@!";

  private boolean multiselect = false;
  private FastHashMap selectedMap = new FastHashMap();
  private VisitorManager visitorManager = new VisitorManager();

  /**
   * Implements the action for conducting a search on users.
   * <p> <p>
   * @param mapping <code>ActionMapping</code> object used to select this instance
   * @param form Optional <code>ActionForm</code> bean for this request (if any)
   * @param request <code>HttpServletRequest</code> object to process
   * @param response <code>HttpServletResponse</code> object to process
   * <p> <p>
   * @return <code>ActionForward</code> instance describing where and how
   * control should be forwarded, or null if the response has already been completed
   * <p> <p>
   * @throws Exception if an error occurs
   */
  public ActionForward processExecute(ActionMapping mapping,
				      ActionForm form,
				      HttpServletRequest request,
				      HttpServletResponse response)
    throws Exception 
  {
    try {
      String parameter = mapping.getParameter();

      this.multiselect = false;
      if (parameter != null && parameter.equals("multiselect")) {
        this.multiselect = true;
      }

      if (this.multiselect) {
        prepareSelectedUsersBean(mapping, form, request);
      }

      boolean executeSearch = ((Boolean) UserUtils.getP(form, "executeSearch")).booleanValue();

      if (null != request.getParameter("btn_action")) {
        executeSearch = true;
      }

      ViewDynaBean view = new ViewDynaBean(VIEW_BEAN_NAME, mapping);
      request.setAttribute(VIEW_BEAN_NAME, view);
      
      UserUtils.setP(view, "useFullName", new Boolean(!VisitorManager.isUsingFMLName()));

      String suggested = request.getParameter("suggested");
      if (!UserUtils.isEmptyString(suggested)) {
        UserUtils.setP(view, "searchResultList", prepareSuggestedUsers(mapping, form, request, view));
	UserUtils.setP(form, "suggested", suggested);
      }
      
      if (executeSearch) {
	UserUtils.setP(view, "searchResultList", findUsers(mapping, form, request, view));
	UserUtils.setP(form, "suggested", "");
      }
      
      UserUtils.setP(view, "multiselect", new Boolean(this.multiselect));
    }
    catch (Exception ex) {
      request.setAttribute(Globals.ERROR_KEY, "error.application");
      return mapping.findForward("failure");
    }
    return mapping.findForward("success");
  }

  protected List findUsers(ActionMapping mapping,
			   ActionForm form,
			   HttpServletRequest request,
			   ViewDynaBean view)
    throws Exception 
  {
    int serviceId = getServiceId(request); 
    UserSearch userSearch = new UserSearch();
      //
      // to make search service specific, call UserSearch.setServiceId
      // if not service specific, set serviceId to -1
      //
    userSearch.setServiceId(serviceId);

    userSearch.setUseFullName(!VisitorManager.isUsingFMLName());
    TransferBeanUtils.copyPropertiesToModel(userSearch, form);
    
    // set the sorting from a key in the ApplicationResources file
    // not supported now
    if (VisitorManager.isUsingFMLName()) {

      String firstName = "FIRST_NAME";
      String middleName = "MIDDLE_NAME";
      String lastName = "LAST_NAME";

      try {

        String sortOrder = getResources(request, "mt.messages").getMessage(getLocale(request), 
									 "mt.user.userName.sortOrder",
									 firstName, 
									 middleName,
									 lastName);
	if (0 == sortOrder.indexOf(firstName)) {
	    userSearch.setSortAttr(firstName);
	}
	else if (0 == sortOrder.indexOf(middleName)) {
	    userSearch.setSortAttr(middleName);
	}
	else {
	    userSearch.setSortAttr(lastName);
	}
      }
      catch (Exception ex) {
      }
    }

    long[] unsortedMatchingVisitors = userSearch.popupSearch();
    long[] matchingVisitors = null;
    
    int numOfVisitors = unsortedMatchingVisitors == null ? 0 : unsortedMatchingVisitors.length;
    if (numOfVisitors > 0) {
      matchingVisitors = new long[numOfVisitors];
      VisitorManager visitorManager = new VisitorManager();
      String[] propNames = new String[1];
      String userId = "USER_ID";
      propNames[0] = userSearch.getSortAttr();
      TableData tblData = visitorManager.getSortedValuesByIdList(unsortedMatchingVisitors, propNames, true);
      for (int i = 0; i < numOfVisitors; i++) {
        matchingVisitors[i] = tblData.getLongValue(i, userId);
      }
    }

    UserUtils.setP(view, "numOfUsers", new Integer(numOfVisitors));

    // pagination support

    int countOfResults = numOfVisitors;

    // entriesPerPage is always not null

    int entriesPerPage = ((Integer) UserUtils.getP(form, "entriesPerPage")).intValue();
    int firstEntry = 0;
    int lastEntry = countOfResults;
    int totalPageNumber = 1;
    int currentPageNumber = 1;

    if (countOfResults > entriesPerPage) {

	
      // currentPageNumber and totalPageNumber are always not null
      currentPageNumber = ((Integer) UserUtils.getP(form, "currentPageNumber")).intValue();
	
      totalPageNumber = countOfResults / entriesPerPage;
      if (countOfResults % entriesPerPage > 0) {
	totalPageNumber++;
      }
      // if the entriesPerPage has been increased
      if (currentPageNumber > totalPageNumber) {
	currentPageNumber = totalPageNumber;
      }
      
      if (currentPageNumber == 0) {
	// first page
	currentPageNumber = 1;
      }
      else {
	firstEntry = (currentPageNumber - 1) * entriesPerPage;
      }
      lastEntry = firstEntry + entriesPerPage;
    }
    else {
      entriesPerPage = countOfResults;
    }
      
    UserUtils.setP(form, "currentPageNumber", new Integer(currentPageNumber));
    UserUtils.setP(form, "totalPageNumber", new Integer(totalPageNumber));

    List dtos = new ArrayList(entriesPerPage);

    for (int i = firstEntry; (i < countOfResults) && (i < lastEntry); i++){
      Visitor visitor = visitorManager.getVisitor(matchingVisitors[i]);
      String userAlias = visitor.getUserAlias();

      if (this.multiselect && this.selectedMap.containsKey(userAlias)) continue;

      ViewDynaBean oneDto = new ViewDynaBean(DTO_BEAN_NAME, mapping);

      UserUtils.setP(oneDto, "firstName", visitor.getStringValue("FIRST_NAME"));
      UserUtils.setP(oneDto, "lastName", visitor.getStringValue("LAST_NAME"));
      UserUtils.setP(oneDto, "fullName", visitor.getStringValue("NAME"));
      UserUtils.setP(oneDto, "userAlias", visitor.getUserAlias());

      // get config flag to determine which name fields to use
      String formattedName = UserUtils.getFormattedName(visitor, 
							getResources(request, "mt.messages"),
							getLocale(request));

      UserUtils.setP(oneDto, "name", formattedName);

      dtos.add(oneDto);
    } // end of for ... loop
    
    return dtos;
  }

  /**
   *
   */
  protected void prepareSelectedUsersBean(ActionMapping mapping,
                                          ActionForm form,
                                          HttpServletRequest request)
                                   throws Exception {
    VisitorManager visitorManager = new VisitorManager();
    Visitor visitor = null;
    String selected = request.getParameter("selected");
    String selectedAlias = request.getParameter("selectedAlias");
    String removeAlias = request.getParameter("removeAlias");

    if (selectedAlias != null && !selectedAlias.equals("")) {
      visitor = visitorManager.getVisitor(selectedAlias);

      if (selected == null || selected.equals("")) {
        selected = selectedAlias;
      }
      else {
        selected += USER_DELIM + selectedAlias;
      }
    }

    String VIEW_BEAN_NAME = "mtSelectedUserView";

    ViewDynaBean view = new ViewDynaBean(VIEW_BEAN_NAME, mapping);
    request.setAttribute(VIEW_BEAN_NAME, view);

    StringBuffer buf = new StringBuffer();
    List dtos = new ArrayList();
    UserUtils.setP(view, "selectedList", dtos);

    selectedMap.clear();
    if (null != selected) {
      StringTokenizer st = new StringTokenizer(selected, USER_DELIM);
      while (st.hasMoreTokens()) {
        String userAlias = st.nextToken();
        if (removeAlias != null && removeAlias.equals(userAlias)) continue;

        ViewDynaBean dto = prepareUserBean(mapping, form, request, userAlias);
        if (null == dto) continue;

        dtos.add(dto);
        selectedMap.put(userAlias, dto);

        buf.append(USER_DELIM);
        buf.append(userAlias);
      }
    }

    int start = USER_DELIM.length();
    int end = buf.length();

    selected = (end > 0) ? buf.substring(start, end) : "";
    UserUtils.setP(form, "selected", selected);
    UserUtils.setP(form, "selectedAlias", "");
    UserUtils.setP(form, "removeAlias", "");
  }

  /**
   *
   */
  protected ViewDynaBean prepareUserBean(ActionMapping mapping,
                                         ActionForm form,
                                         HttpServletRequest request,
                                         String userAlias)
                                  throws Exception {
    Visitor visitor = null;

    try {
      visitor = this.visitorManager.getVisitor(userAlias);
    }
    catch (NoVisitorException e) {
      return null;
    }
    catch (VisitorInactiveException e) {
      return null;
    }
    catch (VisitorException e) {
      return null;
    }

    ViewDynaBean dto = new ViewDynaBean(DTO_BEAN_NAME, mapping);

    UserUtils.setP(dto, "firstName", visitor.getStringValue("FIRST_NAME"));
    UserUtils.setP(dto, "lastName", visitor.getStringValue("LAST_NAME"));
    UserUtils.setP(dto, "fullName", visitor.getStringValue("NAME"));
    UserUtils.setP(dto, "userAlias", visitor.getUserAlias());

    String formattedName = UserUtils.getFormattedName(visitor, 
						      getResources(request, "mt.messages"),
						      getLocale(request));

    UserUtils.setP(dto, "name", formattedName);

    return dto;
  }

  /**
   *
   */
  protected List prepareSuggestedUsers(ActionMapping mapping,
                                       ActionForm form,
                                       HttpServletRequest request,
                                       ViewDynaBean view)
                                throws Exception {
    Visitor[] matchingVisitors = parseSuggestedUsers(request);
    
    int numOfVisitors = matchingVisitors == null ? 0 : matchingVisitors.length;

    if (numOfVisitors > 0) {
      UserUtils.setP(form, 
                     "executeSearch",
                     new Boolean(true));
    }

    UserUtils.setP(view, "numOfUsers", new Integer(numOfVisitors));

    // pagination support

    int countOfResults = numOfVisitors;

    // entriesPerPage is always not null

    int entriesPerPage = ((Integer) UserUtils.getP(form, "entriesPerPage")).intValue();
    int firstEntry = 0;
    int lastEntry = countOfResults;
    int totalPageNumber = 1;
    int currentPageNumber = 1;

    if (countOfResults > entriesPerPage) {

	
      // currentPageNumber and totalPageNumber are always not null
      currentPageNumber = ((Integer) UserUtils.getP(form, "currentPageNumber")).intValue();

      totalPageNumber = countOfResults / entriesPerPage;
      if (countOfResults % entriesPerPage > 0) {
	totalPageNumber++;
      }
      // if the entriesPerPage has been increased
      if (currentPageNumber > totalPageNumber) {
	currentPageNumber = totalPageNumber;
      }
      
      if (currentPageNumber == 0) {
	// first page
	currentPageNumber = 1;
      }
      else {
	firstEntry = (currentPageNumber - 1) * entriesPerPage;
      }
      lastEntry = firstEntry + entriesPerPage;
    }
    else {
      entriesPerPage = countOfResults;
    }
      
    UserUtils.setP(form, "currentPageNumber", new Integer(currentPageNumber));
    UserUtils.setP(form, "totalPageNumber", new Integer(totalPageNumber));

    List dtos = new ArrayList(entriesPerPage);

    for (int i = firstEntry; (i < countOfResults) && (i < lastEntry); i++){
      Visitor visitor = matchingVisitors[i];
      String userAlias = visitor.getUserAlias();

      if (this.multiselect && this.selectedMap.containsKey(userAlias)) continue;

      ViewDynaBean oneDto = new ViewDynaBean(DTO_BEAN_NAME, mapping);

      UserUtils.setP(oneDto, "firstName", visitor.getStringValue("FIRST_NAME"));
      UserUtils.setP(oneDto, "lastName", visitor.getStringValue("LAST_NAME"));
      UserUtils.setP(oneDto, "fullName", visitor.getStringValue("NAME"));
      UserUtils.setP(oneDto, "userAlias", visitor.getUserAlias());

      // get config flag to determine which name fields to use
      String formattedName = UserUtils.getFormattedName(visitor, 
						      getResources(request, "mt.messages"),
						      getLocale(request));
      UserUtils.setP(oneDto, "name", formattedName);

      dtos.add(oneDto);
    } // end of for ... loop
    
    return dtos;
  }

  /**
   *
   */
  protected Visitor[] parseSuggestedUsers(HttpServletRequest request) {
    List list = new ArrayList();
    VisitorManager visitorManager = new VisitorManager();
    String suggested = request.getParameter("suggested");

    if (null != suggested) {
      StringTokenizer st = new StringTokenizer(suggested, USER_DELIM);
      while (st.hasMoreTokens()) {
        String userAlias = st.nextToken();

        if (this.multiselect && this.selectedMap.containsKey(userAlias)) continue;

        try {
          Visitor visitor = visitorManager.getVisitor(userAlias);
          list.add(visitor);
        }
        catch (NoVisitorException e) {
        }
        catch (VisitorInactiveException e) {
        }
        catch (VisitorException e) {
        }
      }
    }

    int size = list.size();
    Visitor[] visitors = new Visitor[size];
    for (int index = 0; index < size; index++) {
      visitors[index] = (Visitor) list.get(index);
    }
 
    return visitors;
  }
}
